Interpreter Pattern
인터프리터 패턴은 어떤 언어에 대해 그 언어의 문법에 대한 표현을 정의하면서 그것을 사용하여 해당 언어로 기술된 문장을 해석하는 해석자를 함께 정의하는 패턴이다.
활용성
정의할 언어의 문법이 간단할 때
문법이 복잡하다면 분법을 정의하는 클래스 계통이 복잡해진다. 이럴 때는 인터프리터 패턴보다 파서와 같은 모듈을 이용하는 것이 더 나은 방법이다.
인터프리터 패턴 사용에 따른 결과
- 문법의 변경과 확장이 쉽다.
- 문법의 구현이 용이하다.
- 복잡한 문법은 관리하기 어렵다.
- 표현식을 해석하는 새로운 방법을 추가할 수 있다.
인터프리터
구조
인터프리터의 구조는 다음과 같다.
C++ 구현
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| void InterpreterPattern::interpret() { Expression* expression = new IntegerConverterExpression(); std::string line1 = "Binary 1234"; std::string line2 = "Hex 1234"; std::string line3 = "Binary 1234"; std::string line4 = "Hex1234fakjwefakljhfawekljh"; std::string line5 = "What did i say?"; std::string line6 = "Hex 987654321"; std::cout<<expression->interpret(line1)<<std::endl; std::cout<<expression->interpret(line2)<<std::endl; std::cout<<expression->interpret(line3)<<std::endl; std::cout<<expression->interpret(line4)<<std::endl; std::cout<<expression->interpret(line5)<<std::endl; std::cout<<expression->interpret(line6)<<std::endl; }
|
1 2 3 4 5
| class Expression { public: virtual std::string interpret(std::string line) = 0; };
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| class IntegerConverterExpression : public Expression { enum Support { HEX, BINARY, };
std::map<Support, std::pair<std::string, Expression*>> expressionMapper;
static const std::string UNSUPPORT; public: IntegerConverterExpression() { expressionMapper[BINARY] = std::make_pair("Binary", new BinaryExpression()); expressionMapper[HEX] = std::make_pair("Hex", new HexExpression()); }
std::string interpret(std::string line) override { for(auto enums : expressionMapper) { auto result = StringParser::contains(enums.second.first, line); if(result.has_value()) return expressionMapper[enums.first].second->interpret(result.value()); }
return UNSUPPORT + line; } };
const std::string IntegerConverterExpression::UNSUPPORT = "Unsupported Expression : ";
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class HexExpression : public Expression { public: std::string interpret(std::string line) override { int value = StringParser::getValue(line); std::stringstream stream; stream << std::hex << value; return stream.str(); } };
class BinaryExpression : public Expression { public: std::string interpret(std::string line) override { int value = StringParser::getValue(line); std::stringstream stream; while(value) { stream << (value & 1); value >>= 1; } return stream.str(); } };
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| class StringParser { StringParser() {}
static std::vector<int> kmpTable(const std::string &s) { int len = s.length(), j = 0; std::vector<int> table(len, 0);
for(int i = 1; i < len; i++) { while (j>0 && s[i] != s[j]) j = table[j-1]; if(s[i] == s[j]) table[i] = ++j; }
return table; } public: static std::optional<std::string> contains(const std::string &pattern, const std::string& context) { std::vector<int> table = kmpTable(pattern); int patternLen = pattern.length(), contextLen = context.length(), j = 0;
for(int i = 0; i < contextLen; ++i){ while(j>0 && context[i] != pattern[j]) j = table[j - 1];
if(context[i] == pattern[j]) if(j == patternLen - 1) return context.substr(i + 1); else j++; } return std::nullopt; }
static int getValue(const std::string& context) { int ret = 0, len = context.length(), index = 0; while(context[index] == ' ') ++index;
while(index < len && '0' <= context[index] && context[index] <= '9') ret = (ret << 3) + (ret << 1) + (context[index++] & 0b1111);
return ret; } };
|
java 구현
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class Client { public static void main(String[] args) { Expression expression = new IntegerConverterExpression(); String line1 = "Binary 1234"; String line2 = "Hex 1234"; String line3 = "Binary 1234"; String line4 = "Hex1234fakjwefakljhfawekljh"; String line5 = "What did i say?"; String line6 = "Hex 987654321";
System.out.println(expression.interpret(line1)); System.out.println(expression.interpret(line2)); System.out.println(expression.interpret(line3)); System.out.println(expression.interpret(line4)); System.out.println(expression.interpret(line5)); System.out.println(expression.interpret(line6)); } }
|
1 2 3
| public interface Expression { String interpret(String line); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| public class IntegerConverterExpression implements Expression{ private static final String UNSUPPORT = "Unsupported Expression : ";
private enum Support{ HEX("Hex"), BINARY("Binary");
private String value;
private Support(String value) { this.value = value; }
public String getValue() { return this.value; } }
private Map<Support, Expression> expressionMapper;
public IntegerConverterExpression() { expressionMapper = new TreeMap<>(); expressionMapper.put(Support.HEX, new HexExpression()); expressionMapper.put(Support.BINARY, new BinaryExpression()); }
@Override public String interpret(String line) { Optional<String> result;
for(Map.Entry<Support, Expression> entry : expressionMapper.entrySet()) { result = StringParser.contains(entry.getKey().getValue(), line); if(result.isPresent()) return entry.getValue().interpret(result.get()); }
return UNSUPPORT + line; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class HexExpression implements Expression{ @Override public String interpret(String line) { int value = StringParser.getValue(line); return Integer.toHexString(value); } }
public class BinaryExpression implements Expression{ public String interpret(String line) { int value = StringParser.getValue(line); return Integer.toBinaryString(value); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| public class StringParser { private StringParser() {}
private static int[] kmpTable(String s) { int len = s.length(), j = 0; int[] table = new int[len];
for(int i = 1; i < len; i++) { while (j>0 && s.charAt(i) != s.charAt(j)) j = table[j-1]; if(s.charAt(i) == s.charAt(j)) table[i] = ++j; }
return table; }
public static Optional<String> contains(final String pattern, final String context) { int[] table = kmpTable(pattern); int patternLen = pattern.length(), contextLen = context.length(), j = 0;
for(int i = 0; i < contextLen; ++i){ while(j>0 && context.charAt(i) != pattern.charAt(j)) j = table[j - 1];
if(context.charAt(i) == pattern.charAt(j)) if(j == patternLen - 1) return Optional.of(context.substring(i + 1)); else j++; } return Optional.empty(); }
public static int getValue(final String context) { int ret = 0, len = context.length(), index = 0; while(context.charAt(index) == ' ') ++index;
while(index < len && '0' <= context.charAt(index) && context.charAt(index) <= '9') ret = (ret << 3) + (ret << 1) + (context.charAt(index++) & 0b1111);
return ret; } }
|